﻿
using LDM.Business.Repository.Repository.Interfaces;
using LitJson;
using Logs.LogCore;
using Microsoft.Extensions.DependencyInjection;
using ThirdParty.Application.Model;
using ThirdParty.Application.Model.ViewModel.Request;
using ThirdParty.Application.Model.ViewModel.Response;
using ThirdParty.Application.ThirdParty.Interfaces;
using Utility.Helpers;
using Utility.Randoms;
using Utility.Webs;
using Logs.Extensions;
using LDM.Business.ServiceAPI.Model.DBModel;
using Logs;

namespace ThirdParty.Application.Tencent;
/// <summary>
/// 微信支付服务
/// </summary>
public class WeiXinPayService : IWeiXinPayService, IScoped
{
    /// <summary>
    /// 系统配置参数
    /// </summary>
    public ISystemConfigRepository systemConfigRepository { protected get; set; }

    public IRandomBuilder RandomBuilder { protected get; set; }

    public RestTemplate RestTemplate { protected get; set; }

    public ILog _logger;

    public WeiXinPayService(ILog logger)
    {
        _logger = logger;
    }


    /// <summary>
    /// 获取微信配置信息 
    /// </summary>
    /// <returns></returns>
    public WxSystemConfig WxSystemConfig()
    {
        var systemConfig = systemConfigRepository.GetSystemConfig();
        return new WxSystemConfig { AppId = systemConfig.WxAppID };
    }

    /// <summary>
    /// 微信支付 
    /// </summary>
    /// <returns></returns>
    public string WxPayQRCodeOrder()
    {

        return string.Empty;
    }



    /// <summary>
    /// 生成直接支付url，支付url有效期为2小时,模式二
    /// </summary>
    /// <param name="reqDto"></param>
    /// <returns>模式二URL</returns>
    public string WxCreateQRCodeOrder(WxCreateOrderReqDto reqDto)
    {
        WxPayData data = new WxPayData();
        data.SetValue("body", reqDto.ProductName);//商品描述
        data.SetValue("attach", reqDto.ProductAttach);//附加数据
        data.SetValue("out_trade_no", reqDto.TradeNo);//随机字符串
        data.SetValue("total_fee", (Math.Round(reqDto.PayAmount * 100, 0)).ToString());//总金额
        data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
        data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
        data.SetValue("goods_tag", reqDto.GoodsTag);//商品标记
        data.SetValue("trade_type", "NATIVE");//交易类型
        data.SetValue("product_id", reqDto.ProductId);//商品ID
        WxPayData result = UnifiedOrder(data);//调用统一下单接口
        string url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接
                                                            //Log.Info(this.GetType().ToString(), "Get native pay mode 2 url : " + url);
        return url;
    }


    /// <summary>
    /// 调用统一下单，获取jsapi调用支付数据,
    /// </summary>
    /// <param name="reqDto"></param>
    /// <returns></returns>
    public WxPayData CreateJSAPICodeOrderResult(WxCreateOrderReqDto reqDto)
    {
        WxPayData data = new WxPayData();
        data.SetValue("body", reqDto.ProductName);
        data.SetValue("attach", reqDto.ProductAttach);
        data.SetValue("out_trade_no", reqDto.TradeNo);
        data.SetValue("total_fee", Math.Round(reqDto.PayAmount * 100, 0).ToString());
        data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
        data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
        data.SetValue("goods_tag", reqDto.GoodsTag);
        data.SetValue("trade_type", "JSAPI");
        data.SetValue("openid", reqDto.OpenId);
        WxPayData result = UnifiedOrder(data);
        return result;
    }

    /// <summary>
    /// 微信支付订单查询
    /// </summary>
    /// <param name="transactionId">微信订单号</param>
    /// <param name="tradeNo">商户订单号</param>
    /// <returns></returns>
    public WxPayData WxOrderQuery(string transactionId, string outTradeNo)
    {
        WxPayData data = new WxPayData();
        if (string.IsNullOrEmpty(transactionId) && string.IsNullOrEmpty(outTradeNo))
        {
            return data;
        }
        //调用订单查询接口,如果内部出现异常则在页面上显示异常原因
        try
        {

            if (!string.IsNullOrEmpty(transactionId))//如果微信订单号存在，则以微信订单号为准
            {
                data.SetValue("transaction_id", transactionId);
            }
            else//微信订单号不存在，才根据商户订单号去查单
            {
                data.SetValue("out_trade_no", outTradeNo);
            }
            return OrderQuery(data);
        }
        catch (Exception ex)
        {
            return data;
        }

    }


    /// <summary>
    /// 通过code换取网页授权access_token和openid的返回数据，正确时返回的JSON数据包如下：
    //{
    // "access_token":"ACCESS_TOKEN",
    //"expires_in":7200,
    //"refresh_token":"REFRESH_TOKEN",
    // "openid":"OPENID",
    // "scope":"SCOPE",
    // "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    //}
    /// </summary>
    /// <param name="code"></param>
    /// <returns></returns>
    public WxUserInfoRespDto GetOpenidAndAccessTokenFromCode(string code)
    {
        var wxUserInfo = new WxUserInfoRespDto();
        try
        {
            if (!string.IsNullOrEmpty(code))
            {
                var systemConfig = systemConfigRepository.GetSystemConfig();
                //构造获取openid及access_token的url
                WxPayData data = new WxPayData();
                data.SetValue("appid", systemConfig.WxAppID);
                data.SetValue("secret", systemConfig.WxAppSecret);
                data.SetValue("code", code);
                data.SetValue("grant_type", "authorization_code");
                string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();
                //请求url以获取数据
                //string result = HttpService.Get(url, systemConfig.WxMchID);
                string result = RestTemplate.SendXMLAsync(HttpMethod.Get, url, null).Result;
                //保存access_token，用于收货地址获取
                JsonData jd = JsonMapper.ToObject(result);
                wxUserInfo.AccessToken = jd.ContainsKey("access_token") ? (string)jd["access_token"] : "";
                wxUserInfo.Openid = jd.ContainsKey("openid") ? (string)jd["openid"] : "";
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
        return wxUserInfo;
    }


    /// <summary>
    /// 统一下单
    /// @param WxPaydata inputObj 提交给统一下单API的参数
    /// @param int timeOut 超时时间
    /// @throws Exception
    /// @return 成功时返回，其他抛异常
    /// </summary>
    /// <param name="inputObj"></param>
    /// <param name="timeOut"></param>
    /// <returns></returns>
    public WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 6)
    {
        string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        //检测必填参数
        if (!inputObj.IsSet("out_trade_no"))
        {
            throw new Exception("缺少统一支付接口必填参数out_trade_no！");
        }
        else if (!inputObj.IsSet("body"))
        {
            throw new Exception("缺少统一支付接口必填参数body！");
        }
        else if (!inputObj.IsSet("total_fee"))
        {
            throw new Exception("缺少统一支付接口必填参数total_fee！");
        }
        else if (!inputObj.IsSet("trade_type"))
        {
            throw new Exception("缺少统一支付接口必填参数trade_type！");
        }
        //关联参数
        if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
        {
            throw new Exception("统一支付接口中，缺少必填参数openid！trade_type为JSAPI时，openid为必填参数！");
        }
        if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
        {
            throw new Exception("统一支付接口中，缺少必填参数product_id！trade_type为JSAPI时，product_id为必填参数！");
        }
        var systemConfig = systemConfigRepository.GetSystemConfig();
        //异步通知url未设置，则使用配置文件中的url
        if (!inputObj.IsSet("notify_url"))
        {
            inputObj.SetValue("notify_url", systemConfig.WxNotifyUrl);//异步通知url
        }
        inputObj.SetValue("spbill_create_ip", systemConfig.WxMchIP);//终端ip	  	    
        inputObj.SetValue("nonce_str", RandomBuilder.GenerateStringFixedLength(10));//随机字符串
        inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_MD5);//签名类型
        return WxPost(inputObj, url);
    }

    /// <summary>
    /// 查询订单
    /// </summary>
    /// <param name="inputObj">提交给查询订单API的参数</param>
    /// <param name="timeOut">超时时间</param>
    /// <returns></returns>
    public WxPayData OrderQuery(WxPayData inputObj, int timeOut = 6)
    {
        string url = "https://api.mch.weixin.qq.com/pay/orderquery";
        //检测必填参数
        if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
        {
            throw new Exception("订单查询接口中，out_trade_no、transaction_id至少填一个！");
        }
        return WxPost(inputObj, url);
    }

    /// <summary>
    /// 从统一下单成功返回的数据中获取微信浏览器调起jsapi支付所需的参数
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="prepay_id"></param>
    /// <param name="wxMchKey"></param>
    /// <returns>微信浏览器调起JSAPI时的输入参数，json格式可以直接做参数用</returns>
    public string GetJsApiParameters(string appid, string prepay_id, string wxMchKey)
    {
        WxPayData jsApiParam = new WxPayData();
        jsApiParam.SetValue("appId", appid);
        jsApiParam.SetValue("timeStamp", Time.GetUnixTimestamp().ToString());
        jsApiParam.SetValue("nonceStr", RandomBuilder.GenerateStringFixedLength(10));
        jsApiParam.SetValue("package", "prepay_id=" + prepay_id);
        jsApiParam.SetValue("signType", "MD5");
        jsApiParam.SetValue("paySign", jsApiParam.MakeSign(wxMchKey));
        string parameters = jsApiParam.ToJson();
        return parameters;
    }

    /// <summary>
    /// 微信post请求
    /// </summary>
    /// <param name="inputObj"></param>
    /// <param name="url"></param>
    /// <param name="timeOut"></param>
    /// <returns></returns>
    private WxPayData WxPost(WxPayData inputObj, string url, int timeOut = 6)
    {
        WxPayData result = new WxPayData();

        var systemConfig = systemConfigRepository.GetSystemConfig();
        if (inputObj.GetValue("appid") == null || string.IsNullOrEmpty(inputObj.GetValue("appid").ToString()))
            inputObj.SetValue("appid", systemConfig.WxAppID);//公众账号ID
        if (inputObj.GetValue("mch_id") == null || string.IsNullOrEmpty(inputObj.GetValue("mch_id").ToString()))
            inputObj.SetValue("mch_id", systemConfig.WxMchID);//商户号
        if (inputObj.GetValue("nonce_str") == null || string.IsNullOrEmpty(inputObj.GetValue("nonce_str").ToString()))
            inputObj.SetValue("nonce_str", RandomBuilder.GenerateStringFixedLength(10));//随机字符串
        if (inputObj.GetValue("sign_type") == null || string.IsNullOrEmpty(inputObj.GetValue("sign_type").ToString()))
            inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_MD5);//签名类型
        if (inputObj.GetValue("sign") == null || string.IsNullOrEmpty(inputObj.GetValue("sign").ToString()))
            inputObj.SetValue("sign", inputObj.MakeSign(systemConfig.WxMchKey));//签名
        string xml = inputObj.ToXml();
        var start = DateTime.Now;//请求开始时间
        string response = string.Empty;
        try
        {
            //string response = HttpService.Post(xml, url, false, timeOut, systemConfig.WxAppID);
            response = RestTemplate.SendXMLAsync(HttpMethod.Post, url, xml).Result;
            _logger.Info($"微信下单数据： {response}");
            result.FromXml(response);
        }
        catch (Exception e)
        {
            _logger.Exception(e).Error($"下单异常，返回接口数据如下： {response}");
        }
        if (result.GetValue("return_code").ToString() != "SUCCESS")
        {
            _logger.Error($"下单失败，返回接口数据如下 {response}");
        }
        //var end = DateTime.Now;
        //int timeCost = (int)((end - start).TotalMilliseconds);
        //ReportCostTime(url, timeCost, result, systemConfig);//测速上报
        return result;
    }



    /// <summary>
    /// 测速上报
    /// </summary>
    /// <param name="inputObj">提交给测速上报接口的参数</param>
    /// <param name="systemConfig">测速上报接口超时时间</param>
    /// <param name="timeOut"></param>
    /// <returns></returns>
    public WxPayData Report(WxPayData inputObj, SystemConfig systemConfig, int timeOut = 1)
    {
        string url = "https://api.mch.weixin.qq.com/payitil/report";
        //检测必填参数
        if (!inputObj.IsSet("interface_url"))
        {
            throw new Exception("接口URL，缺少必填参数interface_url！");
        }
        if (!inputObj.IsSet("return_code"))
        {
            throw new Exception("返回状态码，缺少必填参数return_code！");
        }
        if (!inputObj.IsSet("result_code"))
        {
            throw new Exception("业务结果，缺少必填参数result_code！");
        }
        if (!inputObj.IsSet("user_ip"))
        {
            throw new Exception("访问接口IP，缺少必填参数user_ip！");
        }
        if (!inputObj.IsSet("execute_time_"))
        {
            throw new Exception("接口耗时，缺少必填参数execute_time_！");
        }

        inputObj.SetValue("appid", systemConfig.WxAppID);//公众账号ID
        inputObj.SetValue("mch_id", systemConfig.WxMchID);//商户号
        inputObj.SetValue("user_ip", systemConfig.WxMchIP);//终端ip
        inputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商户上报时间	 
        inputObj.SetValue("nonce_str", RandomBuilder.GenerateStringFixedLength(10));//随机字符串
        inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型
        inputObj.SetValue("sign", inputObj.MakeSign(systemConfig.WxMchKey));//签名
        string xml = inputObj.ToXml();
        //string response = HttpService.Post(xml, url, false, timeOut, systemConfig.WxMchID);
        string response = RestTemplate.SendXMLAsync(HttpMethod.Post, url, xml).Result;
        WxPayData result = new WxPayData();
        result.FromXml(response);
        return result;
    }

    /// <summary>
    /// 测速上报
    /// </summary>
    /// <param name="interface_url">接口URL</param>
    /// <param name="timeCost">接口耗时</param>
    /// <param name="inputObj">参数数组</param>
    /// <param name="systemConfig"></param>
    private void ReportCostTime(string interface_url, int timeCost, WxPayData inputObj, SystemConfig systemConfig)
    {
        //如果不需要进行上报
        if (systemConfig.WxReportLevel == 0)
        {
            return;
        }
        //如果仅失败上报
        if (systemConfig.WxReportLevel == 1 && inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&
         inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS")
        {
            return;
        }

        //上报逻辑
        WxPayData data = new WxPayData();
        data.SetValue("interface_url", interface_url);
        data.SetValue("execute_time_", timeCost);
        //返回状态码
        if (inputObj.IsSet("return_code"))
        {
            data.SetValue("return_code", inputObj.GetValue("return_code"));
        }
        //返回信息
        if (inputObj.IsSet("return_msg"))
        {
            data.SetValue("return_msg", inputObj.GetValue("return_msg"));
        }
        //业务结果
        if (inputObj.IsSet("result_code"))
        {
            data.SetValue("result_code", inputObj.GetValue("result_code"));
        }
        //错误代码
        if (inputObj.IsSet("err_code"))
        {
            data.SetValue("err_code", inputObj.GetValue("err_code"));
        }
        //错误代码描述
        if (inputObj.IsSet("err_code_des"))
        {
            data.SetValue("err_code_des", inputObj.GetValue("err_code_des"));
        }
        //商户订单号
        if (inputObj.IsSet("out_trade_no"))
        {
            data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no"));
        }
        //设备号
        if (inputObj.IsSet("device_info"))
        {
            data.SetValue("device_info", inputObj.GetValue("device_info"));
        }

        try
        {
            Report(data, systemConfig);
        }
        catch (Exception ex)
        {
            //不做任何处理
        }
    }

}

